/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <errno.h>
#include <stdlib.h>
#include <unistd.h>

#include "local_net_def.h"
#include "local_net_dlist.h"
#include "local_net_udp.h"
#include "local_net_utils.h"

#ifdef L0_DEVICE
#include "lwip/ip4_addr.h"
#include "lwip/netif.h"
#include "lwip/netifapi.h"
#include "lwip/sockets.h"
#endif

#ifdef L2_DEVICE
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#endif

#define IP_STR_LEN_MAX 16 // 255.255.255.255
#define IP_STR_LEN_MIN 8  // 0.0.0.0
#define LIMITED_BOARDCAST_IP "255.255.255.255"
#define UDP_COMM_PORT 50000
#define MSG_TYPE_BOARDCAST "broadcast"
#define DEVICE_ID_OBJECT_NAME "\"id\""
#ifdef L0_DEVICE
#define WLAN_NAME "wlan0" // 无线设备使用："wlan0"
#elif defined(L2_DEVICE)
#define WLAN_NAME "eth0" // l2设备插网线时候是eth0
#endif
#define UDP_MSG_SIZE_MAX 1024
#define CN_MINISECONDS_IN_SECOND 1000

#define MSG_SZ 1024
#define EXEC_SUCC 0
#define EXEC_FAILED -1

typedef struct {
    Node_t *list;
#ifdef L0_DEVICE
    osMutexId_t listMutex;
#elif defined(L2_DEVICE)
    pthread_mutex_t listMutex;
#endif
} LocalNetIPDList;
typedef LocalNetIPDList *IPDListHandle;

typedef struct {
#ifdef L0_DEVICE
    osThreadId_t boardcastThread;
    osThreadId_t sendThread;
    osThreadId_t recvThread;
    osMessageQueueId_t sendMsgQueue;
#elif defined(L2_DEVICE)
    pthread_t boardcastThread;
    pthread_t sendThread;
    pthread_t recvThread;
    key_t key;
    int sendMsgQueue;
#endif
    LocalNetThreadStatus boardcastThreadStatus;
    LocalNetThreadStatus sendThreadStatus;
    LocalNetThreadStatus recvThreadStatus;
    LocalNetUdpRecvCb recvCb;
    IPDListHandle ipdList;
} LocalNetUdpController;

typedef struct {
#ifdef L0_DEVICE
    struct in_addr ip;
    in_port_t port;
#elif defined(L2_DEVICE)
    in_addr_t ip;
    uint16_t port;
#endif
} NetData;

typedef struct {
    NetData netData;
    char deviceId[DEVICE_ID_LEN];
} LocalNetUdpIPDNode;

typedef struct {
    NetData netData;
    uint32_t dataLen;
    char data[MSG_SZ];
#ifdef L2_DEVICE
    long dataType;
#endif
} LocalNetUdpSendDataDef;

typedef struct {
    uint32_t dataLen;
    uint8_t interval;
    char data[MSG_SZ];
} LocalNetUdpBoardcastDataDef;

static LocalNetUdpController g_localNetUdpCtl;

#ifdef L0_DEVICE
/**
 * @brief Convert miniseconds to system ticks
 * @param ms Indicates the mimiseconds to convert
 * @return Returns the corresponding ticks of specified time
 */
uint32_t Time2Tick(uint32_t ms)
{
    uint64_t ret;
    ret = ((uint64_t)ms * osKernelGetTickFreq()) / CN_MINISECONDS_IN_SECOND;
    return (uint32_t)ret;
}
#endif
static int DeviceIdCmp(const void *data1, const void *data2)
{
    int ret = -1;
    const LocalNetUdpIPDNode *destIPDNode = (const LocalNetUdpIPDNode *)data1;
    const LocalNetUdpIPDNode *srcIPDNode = (const LocalNetUdpIPDNode *)data2;

    if (!destIPDNode || !srcIPDNode) {
        LOG_E("destIPDNode or srcIPDNode is NULL!");
        return ret;
    }
    if (strlen(destIPDNode->deviceId) == 0 || strlen(srcIPDNode->deviceId) == 0) {
        LOG_E("data has been destroy!");
        return ret;
    }
    return strncmp(destIPDNode->deviceId, srcIPDNode->deviceId, DEVICE_ID_LEN);
}

static int NetDataCmp(const void *data1, const void *data2)
{
    int ret = -1;
    const LocalNetUdpIPDNode *destIPDNode = (const LocalNetUdpIPDNode *)data1;
    const LocalNetUdpIPDNode *srcIPDNode = (const LocalNetUdpIPDNode *)data2;

    if (!destIPDNode || !srcIPDNode) {
        LOG_E("destIPDNode or srcIPDNode is NULL!");
        return ret;
    }

#ifdef L0_DEVICE
    if (destIPDNode->netData.ip.s_addr == srcIPDNode->netData.ip.s_addr) {
        ret = 0;
    }
#elif defined(L2_DEVICE)
    if (destIPDNode->netData.ip == srcIPDNode->netData.ip) {
        ret = 0;
    }
#endif
    return ret;
}

static IPDListHandle LocalNetIPDListInit(void)
{
    IPDListHandle ipdList = (IPDListHandle)malloc(sizeof(LocalNetIPDList));
    if (!ipdList) {
        LOG_E("malloc ipd list handle failed!");
        return NULL;
    }
    ipdList->list = CreateDlist();
    if (!(ipdList->list)) {
        LOG_E("create ipd list failed!");
        goto IPD_LIST_INIT_ERR;
    }

#ifdef L0_DEVICE
    ipdList->listMutex = osMutexNew(NULL);
    if (!(ipdList->listMutex)) {
        LOG_E("create ipd list mutex failed!");
        goto IPD_LIST_INIT_ERR;
    }
#elif defined(L2_DEVICE)
    pthread_mutex_init(&(ipdList->listMutex), NULL);
#endif
    return ipdList;

IPD_LIST_INIT_ERR:
    if (ipdList) {
        free(ipdList);
    }
    return NULL;
}

static void LocalNetIPDListDeinit(IPDListHandle ipdList)
{
    DestroyDlist(&(ipdList->list));

#ifdef L0_DEVICE
    osMutexDelete(ipdList->listMutex);
#elif defined(L2_DEVICE)
    pthread_mutex_destroy(&(ipdList->listMutex));
#endif

    return;
}

static int8_t LocalNetIPDListNodeUpdate(const IPDListHandle ipdList, const LocalNetUdpIPDNode *pIpdNode)
{
    int8_t ret = -1;
#ifdef L0_DEVICE
    osMutexAcquire(ipdList->listMutex, osWaitForever);
#elif defined(L2_DEVICE)
    pthread_mutex_lock(&(ipdList->listMutex));
#endif
    Node_t *node = FindVdlist(ipdList->list, pIpdNode, DeviceIdCmp); //按值查找
    if (node) {                                                      // 存在该DeviceId的成员
        memcpy(node->data, pIpdNode, sizeof(LocalNetUdpIPDNode));
        LOG_I("Update ipdNode list success!");
        ret = 0;
    } else { // 不存在该DeviceId的成员
        LOG_I("Add new device IpdNode data to list!");
        if (!InsertHdlist(ipdList->list, pIpdNode, sizeof(LocalNetUdpIPDNode))) { // 插入头部
            LOG_I("InsertHdlist success!");
            ret = 0;
        } else {
            LOG_E("InsertHdlist failed!");
        }
    }
#ifdef L0_DEVICE
    osMutexRelease(ipdList->listMutex);
#elif defined(L2_DEVICE)
    pthread_mutex_unlock(&(ipdList->listMutex));
#endif
    return ret;
}

/**
 * 暂时不用的函数
static int8_t LocalNetIPDListNodeDelete(const IPDListHandle ipdList, const char* pDeviceId)
{
    int8_t ret = -1;
    LocalNetUdpIPDNode ipdNode = {0};

    memset(&ipdNode, 0, sizeof(LocalNetUdpIPDNode));
    strncpy(ipdNode.deviceId, pDeviceId, DEVICE_ID_LEN);

#ifdef L0_DEVICE
    osMutexAcquire(ipdList->listMutex, osWaitForever);
#elif defined(L2_DEVICE)
    pthread_mutex_lock(&(ipdList->listMutex));
#endif

    if(!DeleteVdlist(ipdList->list, &ipdNode, DeviceIdCmp)) {    //按值删除
        LOG_E("DeleteVdlist failed!");
    }
    else {
        LOG_I("List delete this member success!");
        ret = 0;
    }

#ifdef L0_DEVICE
    osMutexRelease(ipdList->listMutex);
#elif defined(L2_DEVICE)
    pthread_mutex_unlock(&(ipdList->listMutex));
#endif

    return ret;
}
*/

static int8_t LocalNetIPDListDevIdMapNetData(const IPDListHandle ipdList, const char *pDeviceId, NetData *pNetData)
{
    int8_t ret = -1;
    LocalNetUdpIPDNode ipdNode = {0};

    memset(&ipdNode, 0, sizeof(LocalNetUdpIPDNode));

    strncpy(ipdNode.deviceId, pDeviceId, DEVICE_ID_LEN);
#ifdef L0_DEVICE
    osMutexAcquire(ipdList->listMutex, osWaitForever);
#elif defined(L2_DEVICE)
    pthread_mutex_lock(&(ipdList->listMutex));
#endif
    Node_t *node = FindVdlist(ipdList->list, &ipdNode, DeviceIdCmp); //按值查找
    if (node) {                                                      // 存在该DeviceId的成员
        memcpy(&ipdNode, node->data, sizeof(LocalNetUdpIPDNode));
        LOG_I("Get ipdNode data from the list success!");
        memcpy(pNetData, &(ipdNode.netData), sizeof(NetData));
        LOG_I("Get NetData from the ipdNode success!");
        ret = 0;
    } else { // 不存在该DeviceId的成员
        LOG_I("Can not find this member on the list!");
    }

#ifdef L0_DEVICE
    osMutexRelease(ipdList->listMutex);
#elif defined(L2_DEVICE)
    pthread_mutex_unlock(&(ipdList->listMutex));
#endif

    return ret;
}

static int8_t LocalNetIPDListNetDataMapDevId(const IPDListHandle ipdList, const NetData *pNetData, char *pDeviceId)
{
    int8_t ret = -1;
    LocalNetUdpIPDNode ipdNode = {0};

    memset(&ipdNode, 0, sizeof(LocalNetUdpIPDNode));

    memcpy(&(ipdNode.netData), pNetData, sizeof(NetData));
#ifdef L0_DEVICE
    osMutexAcquire(ipdList->listMutex, osWaitForever);
#elif defined(L2_DEVICE)
    pthread_mutex_lock(&(ipdList->listMutex));
#endif
    Node_t *node = FindVdlist(ipdList->list, &ipdNode, NetDataCmp); //按值查找
    if (node) {                                                     // 存在该netData的成员
        memcpy(&ipdNode, node->data, sizeof(LocalNetUdpIPDNode));
        LOG_I("Get ipdNode data from the list success!");
        strncpy(pDeviceId, ipdNode.deviceId, DEVICE_ID_LEN);
        LOG_I("Get deviceId from the ipdNode success!");
        ret = 0;
    } else { // 不存在该DeviceId的成员
        LOG_I("Can not find this member on the list!");
    }

#ifdef L0_DEVICE
    osMutexRelease(ipdList->listMutex);
#elif defined(L2_DEVICE)
    pthread_mutex_unlock(&(ipdList->listMutex));
#endif

    return ret;
}

static int8_t LoaclNetUdpGetDevIdFromMsg(const char *msg, char *pDeviceId)
{
    int8_t ret = -1;
    char *pDeviceIdStr = NULL;

    if (!strstr(msg, MSG_TYPE_BOARDCAST)) {
        LOG_E("msg type is not boardcast!");
        return ret;
    }
    if (!(pDeviceIdStr = strstr(msg, DEVICE_ID_OBJECT_NAME))) {
        LOG_E("Have no id text in the msg!");
        return ret;
    }
    pDeviceIdStr = strstr(pDeviceIdStr, ":");
    pDeviceIdStr = strstr(pDeviceIdStr, "\"");                  // get "id" : ^"XXXX"
    if ('\"' == *(pDeviceIdStr + DEVICE_ID_LEN)) {              // [0]^"XXX...XXX[65]^"
        memcpy(pDeviceId, pDeviceIdStr + 1, DEVICE_ID_LEN - 1); // "[0]^XXX...XXX[64]^"
        pDeviceId[DEVICE_ID_LEN - 1] = '\0';
        ret = 0;
    }
    return ret;
}

#ifdef L0_DEVICE
static void LocalNetUdpBoardCastThread(void *arg)
#elif defined(L2_DEVICE)
static void *LocalNetUdpBoardCastThread(void *arg)
#endif
{
    int32_t optVal = 1;
    struct sockaddr_in boardcastAddr;
    LocalNetUdpBoardcastDataDef *udpBoardcastData = (LocalNetUdpBoardcastDataDef *)arg;

    if (LOCAL_NET_THREAD_INIT == g_localNetUdpCtl.boardcastThreadStatus) {
        g_localNetUdpCtl.boardcastThreadStatus = LOCAL_NET_THREAD_RUNNING;
        LOG_I("boardcastThreadStatus -> LOCAL_NET_THREAD_RUNNING.");
    }

    LOG_I("%s!\r\n", __FUNCTION__);
    LOG_I("%s!\r\n", udpBoardcastData->data);

    memset(&boardcastAddr, 0, sizeof(struct sockaddr_in));
    boardcastAddr.sin_family = AF_INET;
#ifdef L0_DEVICE
    boardcastAddr.sin_addr.s_addr = inet_addr(LIMITED_BOARDCAST_IP);
#elif defined(L2_DEVICE)
    // 获取子网ip
    char *theDeviceName = WLAN_NAME;
    char localSubNet[32] = {0};
    int ret;
    char localIp[32] = {0};
    // 获取自己ip地址
    ret = getLocalIp(theDeviceName, localIp);
    if (ret == 0) {
        // addLogs("########local ip: \n");
        addLogs(localIp);
        size_t i = 0;
        size_t j = 0;
        while (i < 3 && j < strlen(localIp)) {
            localSubNet[j] = *(localIp + j);
            if (*(localIp + j) == '.') {
                i++;
            }
            j++;
        }
        sprintf(localSubNet + strlen(localSubNet), "%s", "255");
        // addLogs("######## localSubNet  is : \n");
        addLogs(localSubNet);
    } else {
        addLogs("######## get local ip failure \n");
    }
    boardcastAddr.sin_addr.s_addr = inet_addr(localSubNet);
#endif
    boardcastAddr.sin_port = htons(UDP_COMM_PORT);
    while (LOCAL_NET_THREAD_RUNNING == g_localNetUdpCtl.boardcastThreadStatus) {
        int32_t boardcastSocket = socket(AF_INET, SOCK_DGRAM, 0);
        if (boardcastSocket < 0) {
            LOG_E("Socket error return %d.", boardcastSocket);
            continue;
        }

        setsockopt(boardcastSocket, SOL_SOCKET, SO_BROADCAST | SO_REUSEADDR, &optVal, sizeof(int));

        while (LOCAL_NET_THREAD_RUNNING == g_localNetUdpCtl.boardcastThreadStatus) {
            int32_t sendBytes = -1;
#ifdef L0_DEVICE
            if ((sendBytes = sendto(boardcastSocket, udpBoardcastData->data, strlen(udpBoardcastData->data), 0,
                                    (struct sockaddr *)&boardcastAddr, sizeof(struct sockaddr))) == -1) {
                LOG_E("sendto fail, errno=%s\n", strerror(errno));
                continue;
            }
            LOG_I("sendBytes : %d,udpBoardcastData->data : %s.", sendBytes, udpBoardcastData->data);
#elif defined(L2_DEVICE)
            // 广播
            if ((sendBytes = sendto(boardcastSocket, udpBoardcastData->data, strlen(udpBoardcastData->data), 0,
                                    (struct sockaddr *)&boardcastAddr, sizeof(struct sockaddr))) == -1) {
                addLogs("sendto fail, errno: ");
                addLogs(strerror(errno));
                continue;
            }
#endif

#ifdef L0_DEVICE
            osDelay(Time2Tick(udpBoardcastData->interval * CN_MINISECONDS_IN_SECOND));
#elif defined(L2_DEVICE)
            sleep(udpBoardcastData->interval);
#endif
        }

        if (boardcastSocket >= 0) {
            close(boardcastSocket);
        }
    }

    if (NULL != udpBoardcastData) {
        free(udpBoardcastData);
    }

    if (LOCAL_NET_THREAD_RELEASE == g_localNetUdpCtl.boardcastThreadStatus) {
        g_localNetUdpCtl.boardcastThreadStatus = LOCAL_NET_THREAD_EXIT;
    } else {
        g_localNetUdpCtl.boardcastThreadStatus = LOCAL_NET_THREAD_ERR;
        LOG_E("boardcastThread release error!");
    }

#ifdef L0_DEVICE
    return;
#elif defined(L2_DEVICE)
    return NULL;
#endif
}

#ifdef L0_DEVICE
static void LocalNetUdpSendThread(void *arg)
#elif defined(L2_DEVICE)
static void *LocalNetUdpSendThread(void *arg)
#endif
{
#ifdef L0_DEVICE
    UNUSED(arg);
#endif
    int32_t sendSocket = -1;
    struct sockaddr_in sendAddr;
    LocalNetUdpSendDataDef *udpSendData = NULL;
    if (LOCAL_NET_THREAD_INIT == g_localNetUdpCtl.sendThreadStatus) {
        g_localNetUdpCtl.sendThreadStatus = LOCAL_NET_THREAD_RUNNING;
    }

    LOG_I("%s! \r\n", __FUNCTION__);

    while (LOCAL_NET_THREAD_RUNNING == g_localNetUdpCtl.sendThreadStatus) {
        sendSocket = socket(AF_INET, SOCK_DGRAM, 0);
        if (sendSocket < 0) {
            LOG_E("Socket error\n");
            goto SEND_SOCK_ERR;
        }
        memset(&sendAddr, 0, sizeof(struct sockaddr_in));
        sendAddr.sin_family = AF_INET;
        while (LOCAL_NET_THREAD_RUNNING == g_localNetUdpCtl.sendThreadStatus) {
#if (PRINT_TIME)
            // test for time
            u32 time1 = getMillionSecond();
#endif
            // recv queue
#ifdef L0_DEVICE
            int32_t res = osMessageQueueGet(g_localNetUdpCtl.sendMsgQueue, &udpSendData, 0, 0);
            if (osOK != res) {
                // LOG_I("mqueue recv data failed!");
                osDelay(Time2Tick(300));
                continue;
            }
#elif defined(L2_DEVICE)
            addLogs("++++++++++++++ recv queue to send udp\r\n");
            udpSendData = (LocalNetUdpSendDataDef *)malloc(sizeof(LocalNetUdpSendDataDef));
            if (!udpSendData) {
                break;
            }
            udpSendData->dataType = 0;
            if (msgrcv(g_localNetUdpCtl.sendMsgQueue, udpSendData, sizeof(LocalNetUdpSendDataDef),
                       udpSendData->dataType, 0) < 0) {
                addLogs("LocalNetUdpSendThread mqueue recv data failed! 111 \r\n");
                free(udpSendData);
                {
                    char errmsg[1024] = {0};
                    sprintf(errmsg, "%d[%s]", errno, strerror(errno));
                    addLogs("errmsg:\r\n");
                    addLogs((const char *)errmsg);
                }
                udpSendData = NULL;
                usleep(300000);
                continue;
            }
            addLogs("+++++++++++++++recv data by queue! recv data: ");
            addLogs("ip: ");
            addLogs("______573________ udpSendData->netData.ip : ");
            addLogs(inet_ntoa(*((struct in_addr *)&(udpSendData->netData.ip))));

            addLogs("++++++++++udpSendData  data: ");
            addLogs(udpSendData->data);
            // LOG_I("recv data by queue! recv data [ip:%s, port:%d, dataLen:%d, data:%s].",
            //     inet_ntoa(*((struct in_addr*)&udpSendData->netData.ip)), udpSendData->netData.port,
            //     udpSendData->dataLen, udpSendData->data);
            sendAddr.sin_addr.s_addr = udpSendData->netData.ip;
#endif
            if (udpSendData == NULL) {
                usleep(300000);
                continue;
            }
            sendAddr.sin_addr.s_addr = udpSendData->netData.ip.s_addr;
            sendAddr.sin_port = htons(UDP_COMM_PORT);
            int32_t sendBytes = -1;
#ifdef L0_DEVICE
            LOG_I("udpSendData->data : %s \n", udpSendData->data ? udpSendData->data : "NULL");
            if (-1 == (sendBytes = sendto(sendSocket, udpSendData->data, strlen(udpSendData->data), 0,
                                          (struct sockaddr *)&sendAddr, sizeof(struct sockaddr)))) {
                LOG_E("sendto fail, errno=%s\n", strerror(errno));
#elif defined(L2_DEVICE)
            if (-1 == (sendBytes = sendto(sendSocket, udpSendData->data, strlen(udpSendData->data), 0,
                                          (struct sockaddr *)&sendAddr, sizeof(sendAddr)))) {
                addLogs("--------557------------sendto fail, errno: ");
                addLogs(strerror(errno));
#endif
                goto SEND_SOCK_ERR;
            }
            LOG_I("sendBytes=%d\n", sendBytes);

            free(udpSendData);
            udpSendData = NULL;

#if (PRINT_TIME)
            // for test time
            {
                char tmp[32] = {0};
                sprintf("%s one loop cost time : %d(ms)", __func__, (int)(getMillionSecond() - time1));
                addLogs(tmp);
            }
#endif
#ifdef L0_DEVICE
            osDelay(Time2Tick(300));
#elif defined(L2_DEVICE)
            usleep(300000);
#endif
        }
    SEND_SOCK_ERR:
        if (udpSendData) {
            free(udpSendData);
            udpSendData = NULL;
        }
        if (sendSocket >= 0) {
            close(sendSocket);
        }
    }

    if (LOCAL_NET_THREAD_RELEASE == g_localNetUdpCtl.sendThreadStatus) {
        g_localNetUdpCtl.sendThreadStatus = LOCAL_NET_THREAD_EXIT;
    } else {
        g_localNetUdpCtl.sendThreadStatus = LOCAL_NET_THREAD_ERR;
        LOG_E("sendThread release error!");
    }

#ifdef L0_DEVICE
    return;
#elif defined(L2_DEVICE)
    return NULL;
#endif
}

#ifdef L0_DEVICE
static void LocalNetUdpRecvThread(void *arg)
#elif defined(L2_DEVICE)
static void *LocalNetUdpRecvThread(void *arg)
#endif
{
    char recvDataBuf[UDP_MSG_SIZE_MAX] = {0};
    int32_t recvSocket = -1;
    int32_t recv_data_len = -1;
    struct sockaddr_in udpRecvAddr;
    struct sockaddr_in udpSenderAddr;
    LocalNetUdpIPDNode ipdNode = {0};
    socklen_t addrlen = sizeof(struct sockaddr);

    if (LOCAL_NET_THREAD_INIT == g_localNetUdpCtl.recvThreadStatus) {
        LOG_I("recvThreadStatus -> LOCAL_NET_THREAD_RUNNING");
        g_localNetUdpCtl.recvThreadStatus = LOCAL_NET_THREAD_RUNNING;
    }

    LOG_I("%s!\r\n", __FUNCTION__);

    while (LOCAL_NET_THREAD_RUNNING == g_localNetUdpCtl.recvThreadStatus) {
        recvSocket = socket(AF_INET, SOCK_DGRAM, 0);
        if (recvSocket < 0) {
            LOG_E("Socket error\n");
            goto RECV_SOCK_ERR;
        }

        memset(&udpRecvAddr, 0, sizeof(struct sockaddr_in));
        memset(&udpSenderAddr, 0, sizeof(struct sockaddr_in));
        udpRecvAddr.sin_family = AF_INET;
        udpRecvAddr.sin_addr.s_addr = INADDR_ANY;
        udpRecvAddr.sin_port = htons(UDP_COMM_PORT);

        if (-1 == bind(recvSocket, (struct sockaddr *)&udpRecvAddr, sizeof(struct sockaddr))) {
            LOG_E("Unable to bind\n");
            goto RECV_SOCK_ERR;
        }

        while (LOCAL_NET_THREAD_RUNNING == g_localNetUdpCtl.recvThreadStatus) {
            memset(recvDataBuf, 0, UDP_MSG_SIZE_MAX);
            recv_data_len =
                recvfrom(recvSocket, recvDataBuf, UDP_MSG_SIZE_MAX, 0, (struct sockaddr *)&udpSenderAddr, &addrlen);
            /*显示发送端的IP地址*/
            LOG_I("receive from %s:%d\n", inet_ntoa(udpSenderAddr.sin_addr), ntohs(udpSenderAddr.sin_port));
            /*显示发送端发来的字串*/
            LOG_I("recevce:%s", recvDataBuf);

            memset(&ipdNode, 0, sizeof(ipdNode));
#ifdef L0_DEVICE
            ipdNode.netData.ip.s_addr = udpSenderAddr.sin_addr.s_addr;
            ipdNode.netData.port = udpSenderAddr.sin_port;
#elif defined(L2_DEVICE)
            ipdNode.netData.ip = udpSenderAddr.sin_addr.s_addr;
            ipdNode.netData.port = udpSenderAddr.sin_port;

            addLogs("==== 2、++++++===========udp=================++++ recevce: ++ipdNode->netData.ip: ");
            addLogs(inet_ntoa(*((struct in_addr *)&(ipdNode.netData.ip))));
#endif
            if (!LoaclNetUdpGetDevIdFromMsg(recvDataBuf, ipdNode.deviceId)) {
                LocalNetIPDListNodeUpdate(g_localNetUdpCtl.ipdList, &ipdNode);
            }

            if (g_localNetUdpCtl.recvCb &&
                !LocalNetIPDListNetDataMapDevId(g_localNetUdpCtl.ipdList, &(ipdNode.netData), ipdNode.deviceId)) {
                g_localNetUdpCtl.recvCb(recvDataBuf, ipdNode.deviceId);
                LOG_I("recv data notice the protocol layer by callback function!");
            } else {
                LOG_E("g_localNetUdpCtl.recvCb is NULL, or can not search this member by netData in IPD list!");
            }

#ifdef L0_DEVICE
            osDelay(Time2Tick(300));
#elif defined(L2_DEVICE)
            usleep(300000);
#endif
        }
    RECV_SOCK_ERR:
        if (recvSocket >= 0) {
#ifdef L0_DEVICE
            closesocket(recvSocket);
#elif defined(L2_DEVICE)
            close(recvSocket);
#endif
        }
    }

    if (LOCAL_NET_THREAD_RELEASE == g_localNetUdpCtl.recvThreadStatus) {
        g_localNetUdpCtl.recvThreadStatus = LOCAL_NET_THREAD_EXIT;
    } else {
        g_localNetUdpCtl.recvThreadStatus = LOCAL_NET_THREAD_ERR;
        LOG_E("recvThread release error!");
    }

#ifdef L0_DEVICE
    return;
#elif defined(L2_DEVICE)
    return NULL;
#endif
}

int8_t LocalNetUdpSend(const char *msg, const char *pDeviceId)
{
    int8_t ret = -1;
    uint16_t msgLen = 0;
    LocalNetUdpSendDataDef *udpSendData;
#if (PRINT_TIME)
    // test for time
    u32 time1 = getMillionSecond();
#endif
    // judge the input msg
    if ((!msg) || (!pDeviceId)) {
        LOG_E("msg or pDeviceId is null");
        return ret;
    }
    msgLen = strlen(msg) + 1;
    if ((msgLen <= 1) || (msgLen > UDP_MSG_SIZE_MAX)) {
        LOG_E("msg size is out of the limit!");
        return ret;
    }
    // malloc to save UdpSendData
    udpSendData = (LocalNetUdpSendDataDef *)malloc(sizeof(LocalNetUdpSendDataDef));
    if (udpSendData == NULL) {
        LOG_E("udpSendData malloc failed!");
        return ret;
    }
    memset(udpSendData, 0, sizeof(LocalNetUdpSendDataDef));
    if (LocalNetIPDListDevIdMapNetData(g_localNetUdpCtl.ipdList, pDeviceId, &(udpSendData->netData))) {
        LOG_E("udp port and ip get failed!");
        goto MAKE_SEND_DATA_ERR;
    }

    // save udpSendData
    udpSendData->dataLen = msgLen;
    memcpy(udpSendData->data, msg, msgLen);

    // udpSendData send queue
#ifdef L0_DEVICE
    if (osOK != osMessageQueuePut(g_localNetUdpCtl.sendMsgQueue, &udpSendData, 0, 0)) {
        LOG_E("osMessageQueuePut error.");
        goto MAKE_SEND_DATA_ERR;
    }
#elif defined(L2_DEVICE)
    udpSendData->dataType = 0;
    if (msgsnd(g_localNetUdpCtl.sendMsgQueue, udpSendData, sizeof(LocalNetUdpSendDataDef), 0) < 0) {
        addLogs("LocalNetUdpSendThread mqueue send data failed! 111 \r\n");
        LOG_E("osMessageQueuePut error.");
        goto MAKE_SEND_DATA_ERR;
    }
    free(udpSendData);
    udpSendData = NULL;
#endif
#if (PRINT_TIME)
    // for test time
    {
        char tmp[32] = {0};
        sprintf("%s success cost time : %d(ms)", __func__, (int)(getMillionSecond() - time1));
        addLogs(tmp);
    }
#endif
    ret = 1;
    return ret;

MAKE_SEND_DATA_ERR:
    ret = -1;
    if (NULL != udpSendData) {
        free(udpSendData);
    }
#if (PRINT_TIME)
    // for test time
    {
        char tmp[32] = {0};
        sprintf("%s failed cost time : %d(ms)", __func__, (int)(getMillionSecond() - time1));
        addLogs(tmp);
    }
#endif

    return ret;
}

int8_t LocalNetUdpBoardcast(const char *msg, uint8_t interval)
{
    int8_t ret = -1;
    int16_t msgLen = 0;
    LocalNetUdpBoardcastDataDef *udpBoardcastData = NULL;
    // judge the input msg
    if (!msg) {
        LOG_E("msg or ipStr is null or out of the limit!");
        return ret;
    }
    msgLen = strlen(msg);
    if ((0 > msgLen) || (UDP_MSG_SIZE_MAX < msgLen + 1)) {
        LOG_E("msg size is out of the limit!");
        return ret;
    }
    // malloc to save udpBoardcastData
    udpBoardcastData = (LocalNetUdpBoardcastDataDef *)malloc(sizeof(LocalNetUdpBoardcastDataDef));
    if (!udpBoardcastData) {
        LOG_E("udpBoardcastData malloc failed!");
        return ret;
    }
    memset(udpBoardcastData, 0, sizeof(LocalNetUdpBoardcastDataDef));
    // save udpBoardcastData
    udpBoardcastData->dataLen = msgLen;
    udpBoardcastData->interval = interval;
    memcpy(udpBoardcastData->data, msg, msgLen);

    g_localNetUdpCtl.boardcastThreadStatus = LOCAL_NET_THREAD_INIT;
    LOG_I("boardcastThreadStatus -> LOCAL_NET_THREAD_INIT.");

    // create udp boardcast thread.
#ifdef L0_DEVICE
    osThreadAttr_t attr;
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.name = "UdpBoardcast";
    attr.stack_size = 1024 * 8;
    attr.priority = 24;
    if (!(g_localNetUdpCtl.boardcastThread =
              osThreadNew((osThreadFunc_t)LocalNetUdpBoardCastThread, udpBoardcastData, &attr))) {
        LOG_E("Could not create the iotcloud thread.");
        goto MAKE_BOARDCAST_DATA_ERR;
    }
#elif defined(L2_DEVICE)
    if (pthread_create(&(g_localNetUdpCtl.boardcastThread), NULL, LocalNetUdpBoardCastThread, udpBoardcastData) !=
        EXEC_SUCC) {
        LOG_E("Could not create the LocalNetUdpBoardCastThread thread.");
        goto MAKE_BOARDCAST_DATA_ERR;
    }
    pthread_detach(g_localNetUdpCtl.boardcastThread);
#endif
    ret = 0;
    return ret;

MAKE_BOARDCAST_DATA_ERR:
    ret = -1;
    if (udpBoardcastData) {
        free(udpBoardcastData);
    }
    return ret;
}

int8_t LocalNetUdpRecvCbReg(LocalNetUdpRecvCb recvCb)
{
    int8_t ret = -1;
    if (NULL == recvCb) {
        LOG_E("recvCb is null!");
        return ret;
    }
    g_localNetUdpCtl.recvCb = recvCb;
    ret = 0;
    return ret;
}

int8_t LocalNetUdpInit(void)
{
    int8_t ret = -1;
    LOG_I("LocalNetUdpInit!\r\n");

    // create ip、port and deviceId list
    g_localNetUdpCtl.ipdList = LocalNetIPDListInit();
    if (!(g_localNetUdpCtl.ipdList)) {
        LOG_E("ipdList init failed!");
        return -1;
    }

    // create udp send msg queue.
#ifdef L0_DEVICE
    g_localNetUdpCtl.sendMsgQueue = osMessageQueueNew(MQ_MSG_NUM_MAX, MQ_MSG_SIZE_MAX, (osMessageQueueAttr_t *)NULL);
    if (NULL == g_localNetUdpCtl.sendMsgQueue) {
        LOG_E("osMessageQueueNew faild!");
        return ret;
    }
    g_localNetUdpCtl.sendThreadStatus = LOCAL_NET_THREAD_INIT;
    // create udp send thread.
    osThreadAttr_t attr;
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.name = "UdpSend";
    attr.stack_size = 1024 * 4;
    attr.priority = 24;
    if ((g_localNetUdpCtl.sendThread = osThreadNew((osThreadFunc_t)LocalNetUdpSendThread, NULL, &attr)) == NULL) {
        LOG_E("Could not create the LocalNetUdpSend thread.");
        return ret;
    }
    LOG_I("recvThreadStatus -> LOCAL_NET_THREAD_INIT");
    g_localNetUdpCtl.recvThreadStatus = LOCAL_NET_THREAD_INIT;
    // create udp recv thread.
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.name = "UdpRecv";
    attr.stack_size = 1024 * 4;
    attr.priority = 24;
    if ((g_localNetUdpCtl.recvThread = osThreadNew((osThreadFunc_t)LocalNetUdpRecvThread, NULL, &attr)) == NULL) {
        LOG_E("Could not create the LocalNetUdpRecv thread.");
        return ret;
    }
#elif defined(L2_DEVICE)
    //获取key
    if ((g_localNetUdpCtl.key = ftok("./", 0xa)) < 0) {
        LOG_E("osMessageQueueNew faild!");
        return ret;
    }
    g_localNetUdpCtl.key = 0;
    g_localNetUdpCtl.sendMsgQueue = msgget(g_localNetUdpCtl.key, IPC_CREAT | 0666);
    if (g_localNetUdpCtl.sendMsgQueue < 0) {
        LOG_E("osMessageQueueNew faild!");
        return ret;
    }

    // create udp send thread.
    g_localNetUdpCtl.sendThreadStatus = LOCAL_NET_THREAD_INIT;
    if (pthread_create(&(g_localNetUdpCtl.sendThread), NULL, LocalNetUdpSendThread, NULL) != EXEC_SUCC) {
        LOG_E("Could not create the LocalNetDevOfflineJudge thread.");
        return ret;
    }
    pthread_detach(g_localNetUdpCtl.sendThread);

    // create udp recv thread.
    g_localNetUdpCtl.recvThreadStatus = LOCAL_NET_THREAD_INIT;
    if (pthread_create(&(g_localNetUdpCtl.recvThread), NULL, LocalNetUdpRecvThread, NULL) != EXEC_SUCC) {
        LOG_E("Could not create the LocalNetCommunicationCtl thread.");
        return ret;
    }
    pthread_detach(g_localNetUdpCtl.recvThread);
#endif

    ret = 0;
    return ret;
}

int8_t LocalNetUdpDeinit(void)
{
    int8_t ret = -1;
    uint8_t iCnt = 0;
    g_localNetUdpCtl.boardcastThreadStatus = LOCAL_NET_THREAD_RELEASE;
    g_localNetUdpCtl.sendThreadStatus = LOCAL_NET_THREAD_RELEASE;
    g_localNetUdpCtl.recvThreadStatus = LOCAL_NET_THREAD_RELEASE;

    LocalNetIPDListDeinit(g_localNetUdpCtl.ipdList);
#ifdef L0_DEVICE
    osMessageQueueDelete(g_localNetUdpCtl.sendMsgQueue);
    while (LOCAL_NET_THREAD_RUNNING == g_localNetUdpCtl.boardcastThreadStatus) {
        iCnt++;
        osDelay(Time2Tick(10));
        if (5 < iCnt) {
            g_localNetUdpCtl.boardcastThreadStatus = LOCAL_NET_THREAD_ERR;
        }
    }
    osThreadTerminate(g_localNetUdpCtl.boardcastThread);
    while (LOCAL_NET_THREAD_RUNNING == g_localNetUdpCtl.sendThreadStatus) {
        iCnt++;
        osDelay(Time2Tick(10));
        if (5 < iCnt) {
            g_localNetUdpCtl.sendThreadStatus = LOCAL_NET_THREAD_ERR;
        }
    }
    osThreadTerminate(g_localNetUdpCtl.sendThread);
    while (LOCAL_NET_THREAD_RUNNING == g_localNetUdpCtl.recvThreadStatus) {
        iCnt++;
        osDelay(Time2Tick(10));
        if (5 < iCnt) {
            g_localNetUdpCtl.recvThreadStatus = LOCAL_NET_THREAD_ERR;
        }
    }
    osThreadTerminate(g_localNetUdpCtl.recvThread);
#elif defined(L2_DEVICE)
    // pthread_cancel
    while (LOCAL_NET_THREAD_RUNNING == g_localNetUdpCtl.boardcastThreadStatus) {
        iCnt++;
        usleep(10000);
        if (5 < iCnt) {
            g_localNetUdpCtl.boardcastThreadStatus = LOCAL_NET_THREAD_ERR;
        }
    }
    //   pthread_cancel(g_localNetUdpCtl.boardcastThread);

    while (LOCAL_NET_THREAD_RUNNING == g_localNetUdpCtl.sendThreadStatus) {
        iCnt++;
        usleep(10000);
        if (5 < iCnt) {
            g_localNetUdpCtl.sendThreadStatus = LOCAL_NET_THREAD_ERR;
        }
    }
    //   pthread_cancel(g_localNetUdpCtl.sendThread);

    while (LOCAL_NET_THREAD_RUNNING == g_localNetUdpCtl.recvThreadStatus) {
        iCnt++;
        usleep(10000);
        if (5 < iCnt) {
            g_localNetUdpCtl.recvThreadStatus = LOCAL_NET_THREAD_ERR;
        }
    }
    //   pthread_cancel(g_localNetUdpCtl.recvThread);
#endif
    ret = 0;
    return ret;
}

/**
 * @brief Get the Local Mac Addr
 *
 * @param ethName 网卡设备名称
 * @param macAddr 获取到的mac地址
 * @param macSize macAddr的总大小
 * @return int
 */
int getLocalMacAddr(const char *ethName, char *macAddr, int macSize)
{
#ifdef L0_DEVICE
    memset(macAddr, 0, macSize);
    strcpy(macAddr, "001B44113AB7");
    return 0;
#elif defined(L2_DEVICE)
    int fd;
    int interfaceNum = 0;
    struct ifreq buf[16];
    struct ifconf ifc;
    struct ifreq ifrcopy;

    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket");
        close(fd);
        return -1;
    }

    ifc.ifc_len = sizeof(buf);
    ifc.ifc_buf = (caddr_t)buf;
    if (!ioctl(fd, SIOCGIFCONF, (char *)&ifc)) {
        interfaceNum = ifc.ifc_len / sizeof(struct ifreq);

        while (interfaceNum-- > 0) {
            if (!strcmp(ethName, buf[interfaceNum].ifr_name)) {
                // ignore the interface that not up or not runing
                ifrcopy = buf[interfaceNum];
                if (ioctl(fd, SIOCGIFFLAGS, &ifrcopy)) {
                    printf("ioctl: %s [%s:%d] \n", strerror(errno), __FILE__, __LINE__);
                    close(fd);
                    return -1;
                }
                // get the mac of this interface
                if (!ioctl(fd, SIOCGIFHWADDR, (char *)(&buf[interfaceNum]))) {
                    memset(macAddr, 0, macSize);
                    snprintf(macAddr, macSize, "%02x:%02x:%02x:%02x:%02x:%02x",
                             (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[0],
                             (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[1],
                             (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[2],
                             (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[3],
                             (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[4],
                             (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[5]);
                } else {
                    printf("ioctl: %s [%s:%d] \n", strerror(errno), __FILE__, __LINE__);
                    close(fd);
                    return -1;
                }
                close(fd);
                return 0;
            }
        }
    } else {
        printf("ioctl: %s [%s:%d] \n", strerror(errno), __FILE__, __LINE__);
        close(fd);
        return -1;
    }

    close(fd);
    return -1;
#endif
}